package com.cdelink.xzgy.ftp.config;


import com.cdelink.xzgy.ftp.common.ReturnData;
import com.cdelink.xzgy.ftp.exception.BaseException;
import com.cdelink.xzgy.ftp.util.FtpUtil;
import com.cdelink.xzgy.ftp.util.RedisUtil;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Objects;

/**
 * 统一配置类
 */
@Configuration
@ControllerAdvice
public class AppConfig implements WebMvcConfigurer {
    @Lazy
    @Autowired
    RedisUtil redisUtil;

    static final String HEADER = "header";

    /**
     * 全局异常捕获处理
     *
     * @param exception
     * @return
     */
    @ResponseBody
    @ExceptionHandler(Exception.class)
    //@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public ReturnData handleServerException(Exception exception) {
        int httpStatus = ReturnData.CODE_FAIL;
        String msg = exception.getMessage();
        Class<?> exceptionClazz = exception.getClass();
        if (exception instanceof BaseException) {
            httpStatus = ((BaseException) exception).getExceptionCode();
        } else if (exception instanceof MethodArgumentNotValidException) {
            httpStatus = ReturnData.CODE_INVALID_DATA;
            msg = ((MethodArgumentNotValidException) exception).getBindingResult()
                    .getAllErrors().get(0).getDefaultMessage();
        } else if (Objects.equals(MissingServletRequestParameterException.class, exceptionClazz)) {
            httpStatus = ReturnData.BAD_REQUEST;
        } else if (Objects.equals(HttpRequestMethodNotSupportedException.class, exceptionClazz)) {
            httpStatus = ReturnData.CODE_NOT_SUPPORTED;
        } else if (Objects.equals(IllegalArgumentException.class, exceptionClazz)) {
            msg = String.format("非法参数异常，%s", exception.getMessage());
        } else {
            exception.printStackTrace();
            msg = exception.getMessage();
        }
        return new ReturnData(httpStatus)
                .setCode(httpStatus)
                .setMessage(msg);
    }

    /**
     * redisUtil交于spring容器处理
     *
     * @param redisTemplate
     * @return
     */
    @Bean
    public RedisUtil createRedisUtil(RedisTemplate<String, Object> redisTemplate) {
        return new RedisUtil(redisTemplate);
    }

    /**
     * redisTemplate交于spring容器管理
     *
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jacksonSerial = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        //指定要序列化的域
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //设定非final修饰的类，比如String会跑出异常
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jacksonSerial.setObjectMapper(om);
        template.setValueSerializer(jacksonSerial);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        //设置hash key和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSerial);
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    public RestTemplate createRestTemplate() {
        return new RestTemplate();
    }

    /**
     * ftpUtil
     *
     * @return
     */
    @Bean
    public FtpUtil createFtpUtil() {
        return new FtpUtil();
    }

    /**
     * 拦截器放行swagger资源
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        AuthorizationInterceptor interceptor = new AuthorizationInterceptor(redisUtil);
        registry.addInterceptor(interceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
    }


}
